<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script type="text/javascript">
        //源数据
        let person = {
            name: '张三',
            age: 18,
        }

        //vue2中的响应式原理
        /*
        let p = {}
        Object.defineProperty(p, 'name', {
            get() {
                //读取name时调用
                return person.name
            },
            set(value) {
                //修改name时调用，但新增
                person.name = value
                console.log('有人修改了name属性，我要更新页面了')
            },
            configurable: true,
        })
        Object.defineProperty(p, 'age', {
            get() {
                return person.age
            },
            set(value) {
                person.age = value
                console.log('有人修改了age属性，我要更新页面了')
            },
            configurable: true,
        })

        console.log(person, p);

        //修改属性，有响应式
        p.name = '李四'
        p.age = 90
        //添加属性，没有响应式
        // p.sex = '男'
        // console.log(person, p);
        //删除属性，没有响应式
        // delete p.name
        // console.log(person, p);
        */
        
        //vue3中的响应式原理
        //Proxy是ES6中window上的一个内置函数，用于实现创建代理对象。构造函数第一个参数是源对象，第二个参数配置代理
        const p = new Proxy(person, {
            get(target, propertyName) {
                //get方法第一个参数target是源对象，即person，第二个参数是属性名
                console.log(`有人读取p的${propertyName}属性`)
                //正常写法
                // return target[propertyName]
                //反射写法
                return Reflect.get(target, propertyName)
            },
            set(target, propertyName, value) {
                //新增/修改属性会调用这里set
                console.log(`有人新增或修改p的${propertyName}属性，我要去更新页面了`)
                // target[propertyName] = value
                return Reflect.set(target, propertyName, value)
            },
            deleteProperty(target, propertyName) {
                //删除属性时调用
                console.log(`有人删除p的${propertyName}属性，我要去更新页面了`)
                // return delete target[propertyName]
                return Reflect.deleteProperty(target, propertyName)
            }
        })
        console.log(p)

        //对代理对象p属性的增删改查，可以映射到源对象person上
        p.name = '李四'
        console.log(p, person)
        p.sex = '男'
        console.log(p, person)
        delete p.name
        console.log(p, person)

        //反射 window上有一个Reflect对象，可以实现反射操作；另外Reflect上也有Object上的一些方法，比如defineProperty
        let obj = {a: 1, b: 2}
        const a = Reflect.get(obj, 'a')
        console.log(a)
        Reflect.set(obj, 'b', 123)
        console.log(obj)
        Reflect.deleteProperty(obj, 'b')
        console.log(obj)

    </script>
</body>
</html>